
#pragma once

#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <memory>
#include "Log.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Thread.hpp"

// 单例模式,一个类只允许创建一个对象,负责管理全局的资源
// 线程安全的单例线程池实现
// 懒汉模式,核心是延迟加载,用时才加载
namespace ThreadPoolModule
{
    using namespace LogModule;
    using namespace ThreadModule;
    using namespace LockModule;
    using namespace CondModule;
    void DefaultTest()
    {
        while (true)
        {
            LOG(Loglevel::DEBUG) << "我是一个测试线程";
            sleep(1);
        }
    }
    using thread_t = std::shared_ptr<Thread>;
    const static int defaultnum = 16;   //这里线程池要执行的是长任务,所以要将线程适当增加 
    template <typename T>
    class ThreadPool
    {
    private:
        // 单例模式不允许赋值构造和拷贝构造,需要将两种函数设为私有并且delate
        ThreadPool(const ThreadPool<T> &) = delete;
        ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;
        bool IsEmpty() { return _taskq.empty(); }
        void HandlerTask(std::string name)
        {
            LOG(Loglevel::INFO) << "线程" << name << "进入HandleTask逻辑";
            while (true)
            {
                // 1.拿任务
                T t;
                {
                    LockGard lock(_mutex);
                    while (IsEmpty() && _isrunning)
                    {
                        _wait_num++;
                        _cond.Wait(_mutex);
                        _wait_num--;
                    }
                    if (IsEmpty() && !_isrunning) // 队列为空并且线程退出,就退出
                    {
                        break;
                    }
                    // 其余情况都正常拿任务处理任务
                    t = _taskq.front();
                    _taskq.pop();
                    // 2.处理任务
                    t(); // 规定未来任何任务都要支持()重载
                }
            }
            LOG(Loglevel::INFO) << "线程" << name << "退出";
        }

    public:
        static ThreadPool<T> *getInstance()
        {
            if (instance == nullptr)
            {
                LockGard lock(mutex);
                if (instance == nullptr) // 双重if判定,避免不必要的锁竞争
                {
                    LOG(Loglevel::INFO) << "单例首次被执行,需要加载对象...";
                    instance = new ThreadPool<T>();
                    instance->Start();
                }
            }
            return instance;
        }
        ThreadPool(int num = defaultnum)
            : _num(num), _wait_num(0), _isrunning(false)
        {
            // 创建num个线程
            for (int i = 0; i < _num; i++)
            {
                _threads.push_back(std::make_shared<Thread>(std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1)));
                // 构建 make_shared 对象，当我们传递名字的时候，需要带上 placeholder,占位
                LOG(Loglevel::INFO) << "构建线程" << _threads.back()->Name() << "对象成功";
            }
        }
        void Equeue(T in) //注意这里要去掉引用
        {
            LockGard lock(_mutex); // 生产队列是公共资源,需要保护
            if (!_isrunning)       // 如果停止运行就不再生产
                return;
            //_taskq.push(std::move(in)); // move资源转移,避免了不必要的拷贝,提高性能
            _taskq.push(in);
            if (_wait_num > 0)
            {
                _cond.Notify();
            }
        }
        void Start()
        {
            if (_isrunning)
                return;
            _isrunning = true; // 注意一定要在线程开始前就置为运行状态
            for (auto &thread_ptr : _threads)
            {
                thread_ptr->Start();
                LOG(Loglevel::INFO) << "线程启动" << thread_ptr->Name() << "成功";
            }
        }
        void Wait()
        {
            for (auto &thread_ptr : _threads)
            {
                thread_ptr->Join();
                LOG(Loglevel::INFO) << "线程" << thread_ptr->Name() << "回收成功";
            }
        }
        void Stop()
        {
            LockGard lock(_mutex);
            // 停止的三个条件
            // 1.必须由线程自己回收自己
            // 2.必须完成历史任务
            // 3.不能再有数据入队列
            if (_isrunning)
            {
                _isrunning = false; // 解决3
                if (_wait_num > 0)  // 解决1和2
                {
                    // 唤醒之后处理完任务且停止运行就自己break退出了
                    _cond.NotifyAll();
                }
            }
        }
        ~ThreadPool()
        {
        }

    private:
        std::vector<thread_t> _threads;
        int _num;             // 线程数量
        int _wait_num;        // 等待中的线程数量
        std::queue<T> _taskq; // 任务队列
        Mutex _mutex;
        Cond _cond;
        bool _isrunning;
        // 两个是全局的
        static ThreadPool<T> *instance;
        static Mutex mutex; // 用来保护       单例
    };
    template <typename T>
    ThreadPool<T> *ThreadPool<T>::instance = nullptr;
    template <typename T>
    Mutex ThreadPool<T>::mutex;
}